import { ExclamationCircleOutlined } from '@ant-design/icons';
import { Avatar, Button, Modal, Space, Table, TablePaginationConfig } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { AuthenticationService, User } from 'my-web-core/auth';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import EditUser from '@/features/users/components/EditUser';
import UsersService from '@/features/users/services/users-service';
import { useWindowInnerSize } from '@/shared/hooks/general-hook';

import '@/features/users/components/UserList.css';

function UserList() {
  // Union type. Added [key] to [User] type. This is for ant data table component.
  type UserType = User & { key: string };

  const selectedIdsRef = useRef<string[]>([]);
  const navigate = useNavigate();
  const { confirm } = Modal;
  const [data, setData] = useState<UserType[]>();
  const [loading, setLoading] = useState<boolean>(false);
  const [open, setOpen] = useState(false);
  const [rowSelection, setRowSelection] = useState<any>();
  const tableSize = useWindowInnerSize({ heightOffset: 285 });
  const tableScrollSize = useWindowInnerSize({ heightOffset: 270 });
  const userService = new UsersService();

  // Option 1: Defines object to contains pageIndex.
  // Why object?
  // When we need to refresh data at first page we have to make sure effect is triggered.
  // It current page index is already 1 then number type cannot trigger effect.
  // But we can assign a new object to achieve this goal.
  // const [pagingParam, setPagingParam] = useState<{
  //   pageIndex: number,
  // }>({
  //   pageIndex: 1,
  // });

  const [pagination, setPagination] = useState<TablePaginationConfig>({
    current: 1,
    pageSize: 20,
    total: 0,
  });

  const columns: ColumnsType<UserType> = [
    {
      title: '操作',
      key: 'action',
      width: 100,
      fixed: 'left',
      render: (_, item: UserType) => (
        <Button onClick={() => navigate(`/users/detail/${item.id}`)}>详情</Button>
      ),
    },
    {
      title: '头像',
      dataIndex: 'avatarUrl',
      key: 'avatarUrl',
      width: 100,
      render: (_: any, item: UserType) => <Avatar src={item.avatarUrl} />,
    },
    {
      title: '用户名',
      dataIndex: 'username',
      key: 'username',
      width: 130,
    },
    {
      title: '昵称',
      dataIndex: 'fullName',
      key: 'fullName',
      ellipsis: true,
    },
  ];

  // Option 2: Uses [useRef] to store the function delcared inside [useEffect].
  // const queryRef = useRef<(pageSize: number, pageIndex: number) => void>();

  // This ref also can be called inside effect without warning.
  // const queryRef = useRef((pageSize: number, pageIndex: number): void => {
  //   UserService.queryAccountGroupUsers(pageSize, pageIndex).then((res) => {
  //     // Queries data and converts the union type.
  //     const list = res.map((p) => {
  //       return {
  //         ...p,
  //         key: p.id,
  //       };
  //     }) as UserType[];

  //     // Updates data for table.
  //     setData(list);

  //     // Updates total count for pagination.
  //     setTotalCount(200);
  //   }).finally(() => setLoading(false));
  // });

  useEffect(() => {
    // Enables data table loading status.
    setLoading(true);

    userService
      .queryAccountGroupUsers(pagination.pageSize!, pagination.current!)
      .then((res) => {
        // Queries data and converts the union type.
        const list = res.map((p) => {
          return {
            ...p,
            key: p.id,
          };
        }) as UserType[];

        // Updates data for table.
        setData(list);

        // TODO: Uses real number returned from api.
        // Updates total count for pagination only.
        // DON'T update [pagination] to entire new object.
        // Otherwise it would trigger [useEffect] again. Dead loop.
        pagination.total = 200;
        setPagination(pagination);
      })
      .finally(() => setLoading(false));

    // Defines function here to meet [useEffect] policy.
    // function query(pageSize: number, pageIndex: number): void {
    //   userService.queryAccountGroupUsers(pageSize, pageIndex).then((res) => {
    //     // Queries data and converts the union type.
    //     const list = res.map((p) => {
    //       return {
    //         ...p,
    //         key: p.id,
    //       };
    //     }) as UserType[];

    //     // Updates data for table.
    //     setData(list);

    //     // Updates total count for pagination only.
    //     // DON'T update [pagination] to entire new object.
    //     // Otherwise it would trigger [useEffect] again. Dead loop.
    //     pagination.total = 200;
    //     setPagination(pagination);
    //   }).finally(() => setLoading(false));
    // };

    // // Stores this function in ref then it can ben called outside [useEffect].
    // queryRef.current = query;

    // // query(pageSize, 1);
    // query(pageSize, pagination.current!);
    // }, []);
  }, [pagination]);

  function onChange(newPagination: TablePaginationConfig): void {
    // queryRef.current!(pageSize, newPagination.current!);

    // Updates pagination for data table.
    setPagination({
      ...pagination,
      pageSize: newPagination.pageSize,
      current: newPagination.current,
      // total: totalCount,
    });
  }

  function reload(): void {
    // Reloads data and back to first page.
    // queryRef.current!(pageSize, 1);

    // Updates pagination for data table.
    setPagination({
      ...pagination,
      current: 1,
      // total: totalCount,
    });
  }

  function onOk(): void {
    reload();

    // Closes model window.
    setOpen(false);
  }

  function onClickSetShowRowSelection(): void {
    if (rowSelection) {
      setRowSelection(undefined);
    } else {
      setRowSelection({
        onChange: (selectedRowKeys: React.Key[], _selectedRows: UserType[]) => {
          selectedIdsRef.current = selectedRowKeys.map((p) => p.toString());
        },
        getCheckboxProps: (record: UserType) => ({
          disabled:
            record.isAccountGroupCreator || record.id === AuthenticationService.currentUser?.id, // Column configuration not to be checked
          // name: record.name,
        }),
      });
    }
  }

  function deleteData(): void {
    confirm({
      title: '确认删除？',
      icon: <ExclamationCircleOutlined />,
      content: `删除所选 ${selectedIdsRef.current.length} 项数据吗？`,
      async onOk() {
        await userService.delete(selectedIdsRef.current);
        reload();
      },
    });
  }

  function buildTableTitle() {
    return (
      <Space>
        <Button type="primary" onClick={() => setOpen(true)}>
          添加
        </Button>
        <Button onClick={onClickSetShowRowSelection}>{rowSelection ? '取消' : '选择'}</Button>
        {rowSelection && (
          <Button disabled={selectedIdsRef.current.length === 0} onClick={deleteData}>
            删除
          </Button>
        )}
      </Space>
    );
  }

  return (
    <>
      <style
        dangerouslySetInnerHTML={{
          __html: `
          #userListUserTableContainer .ant-table-container {
            height: ${tableSize.height}px;
          }
        `,
        }}
      />
      <div id="userListUserTableContainer">
        <Table
          rowSelection={rowSelection}
          bordered={true}
          loading={loading}
          rowKey={(p) => p.id!}
          columns={columns}
          dataSource={data}
          pagination={pagination}
          scroll={{ y: tableScrollSize.height }}
          title={() => buildTableTitle()}
          onChange={onChange}
        />
      </div>
      <Modal title="添加用户" open={open} footer={null}>
        <EditUser ok={onOk} cancel={() => setOpen(false)} />
      </Modal>
    </>
  );
}

export default UserList;
